#pragma once

// -----------------------------------------------------------------------------

#include "Win32.MemoryBuffer.h"

#include <Winerror.h>
#include <malloc.h>
#include <TCHAR.h>
#include <strsafe.h>

namespace Kif
{
namespace Win32
{

#define SizeOf(arr) ((sizeof(arr)/sizeof(TCHAR))-1)
#define sizeOf(arr) ((sizeof(arr)/sizeof(char))-1)
#define IsNumber(c) (((c) >= '0') && ((c) <= '9'))

// -----------------------------------------------------------------------------

class AnsiString
{
private:
   char  *buffer;
   size_t length;

public:

   static const size_t MaxLength = STRSAFE_MAX_CCH * sizeof(TCHAR);
   static const size_t MaxStringLength = 512;
   static const int BadCompareReturnValue = -999999;
   static const int BadIndexValue = -9999999;

   inline size_t GetLength()
   {  return(length); }
   inline char *GetBuffer()
   {  return(buffer); }

   void Dispose()
   {
      if (buffer != NULL)
         Kif::Win32::Memory::free(buffer);
      buffer = NULL;
      length = 0;
   }  // end of Dispose

   AnsiString(char *buffer,size_t length)
   {
      this->buffer = buffer;
      this->length = length;
   }  // end of AnsiString (ctor)

   AnsiString()
   {
      buffer = NULL;
      length = 0;
   }  // end of AnsiString (ctor)

   char *Copy(wchar_t *wideString, size_t length)
   {
      if (length <= 0)
         return(NULL);

      if (buffer != NULL)
         Kif::Win32::Memory::free(buffer);

      this->buffer = (char*)Kif::Win32::Memory::alloc(sizeof(char)+(length+1));
      this->length = length;

      char *pBuff = buffer;
      size_t i;
      for (i=0; i < length; i++,pBuff++,wideString++)
         *pBuff = (char)*wideString;
     *pBuff = NULL;

      return buffer;
   }  // end of Copy

   static inline size_t getLength(wchar_t *buffer)
   {
      size_t blen;
      HRESULT HResult = StringCbLengthW(buffer,MaxLength,&blen);
      if (HResult == S_OK)
         return(blen/sizeof(wchar_t));
      return((size_t)-1);
   }  // end of getLength

   char *Copy(wchar_t *buffer)
   {
      size_t length = getLength(buffer);
      return(Copy(buffer,length));
   }  // end of Copy

   static int Copy(char *outString, int maxOutLength, char *inString)
   {
      int c = 0;
      while ((*inString) && (c < maxOutLength))
      {
         *outString = *inString;
         outString++;
         inString++;
         c++;
      }
      if (c+1 >= maxOutLength)
         throw L"max output length exceeded";
      *outString = NULL;
      return(c);
   }  // end of Copy

   static int Copy(wchar_t *outString, int maxOutLength, wchar_t *inString)
   {
      int c = 0;
      while ((*inString) && (c < maxOutLength))
      {
         *outString = *inString;
         outString++;
         inString++;
         c++;
      }
      if (c+1 >= maxOutLength)
         throw L"max output length exceeded";
      *outString = NULL;
      return(c);
   }  // end of Copy

   static int Compare(char *string1, char *string2)
   {
      while (*string1 && *string2)
      {
         if ((*string1) != (*string2))
            break;
         string1++;
         string2++;
      }
      return(*string2 - *string1);
   }  // end of Copy

   /// <summary>calculate string length using given buffer</summary>
   static inline size_t getLength(char *buffer)
   {
      size_t c = 0;
      while(*buffer)
      {
         buffer++;
         c++;
      }
      return(c);
   }  // end of getLength

   /// <summary>duplicate buffer</summary>
   static inline char *duplicate(char *buffer,DWORD bufferLength)
   {
      return(Kif::Win32::Memory::duplicate<char>(buffer,bufferLength));
   }  // end of duplicate

   /// <summary>duplicate buffer</summary>
   static inline char *duplicate(char *buffer)
   {
      size_t length = getLength(buffer);
      return(Kif::Win32::Memory::duplicate<char>(buffer,(DWORD)length));
   }  // end of duplicate

   static void Clear(char *outBuffer, size_t bufferSize, char clearValue)
   {
      Memory::clear<char>(outBuffer,(DWORD)bufferSize,clearValue);
   }

   AnsiString(wchar_t *wideString,size_t length)
   {
      this->buffer = NULL;
      this->length = length;
      Copy(wideString,length);
   }  // end of AnsiString (ctor)

  ~AnsiString()
   {
      Dispose();
   }  // end of AnsiString (dtor)
}  ;  // end of AnsiString class

// -----------------------------------------------------------------------------

class String
{

public:
   size_t length;

private:

   Diagnostics::Result lastResult;
   MemoryBuffer<TCHAR> string;

   inline void FreeBuffer()
   {
      length = 0;
      string.Dispose();
   }  // end of FreeBuffer

   inline bool ValidateBuffer()
   {
      if (string.Buffer != NULL)
      {
         if (length == 0)
            length = string.GetSize() - 1;
      }
      else
         length = 0;
      return(true);
   }  // end of ValidateBuffer

public:

   static const size_t MaxLength = STRSAFE_MAX_CCH * sizeof(TCHAR);
   static const size_t MaxStringLength = 512;
   static const int BadCompareReturnValue = -999999;
   static const int BadIndexValue = -9999999;

   String()
   {
      length = 0;
      lastResult.HResult = S_OK;
   }  // end of Init string constructure (ctor)

   String(char *buffer)
   {
      length = 0;
      lastResult.HResult = S_OK;
      Copy(buffer);
   }

   String(TCHAR *buffer)
   {
      length = 0;
      lastResult.HResult = S_OK;
      Copy(buffer);
   }

   /// <summary>Dispose of unmanaged resources</summary>
   inline void Dispose()
   {
      FreeBuffer();
   }  // end of Dispose

   /// <summary>return the last result</summary>
   inline Diagnostics::Result *GetLastResult()
   {
      return(&lastResult);
   }  // end of GetLastHResult

   /// <summary>return true if last HRESULT == S_OK</summary>
   inline bool Success()
   {
      return(lastResult.HResult == S_OK);
   }  // end of Success

   /// <summary>return an empty string</summary>
   static inline TCHAR *GetEmptyString()
   {
      return((TCHAR*)_T(""));
   }  // end of GetEmptyString

   /// <summary>duplicate buffer</summary>
   static inline TCHAR *duplicate(TCHAR *buffer,size_t bufferLength)
   {
      return(Kif::Win32::Memory::duplicate<TCHAR>(buffer,(DWORD)bufferLength));
   }  // end of duplicate

   /// <summary>duplicate buffer</summary>
   static inline TCHAR *duplicate(TCHAR *buffer)
   {
      return(Kif::Win32::Memory::duplicate(buffer));
   }  // end of duplicate

   /// <summary>calculate string length using given buffer</summary>
   static inline size_t getLength(wchar_t *buffer)
   {
      return(AnsiString::getLength(buffer));
   }  // end of getLength

   static inline size_t getLength(char *buffer)
   {  return(AnsiString::getLength(buffer)); }

   /// <summary>calculate string length using given buffer</summary>
   static inline size_t GetLengthNonPrintable(TCHAR *buffer)
   {
      TCHAR *p = buffer;
      while(*p && (*p >= ' '))
         p++;
      return(p - buffer);
   }  // end of GetLengthNonPrintable

   /// <summary>calculate string length using given buffer</summary>
   static inline size_t GetLength(TCHAR *buffer)
   {
      size_t blen;
      HRESULT HResult = StringCbLength(buffer,MaxLength,&blen);
      if (HResult == S_OK)
         return(blen/sizeof(TCHAR));
      return((size_t)-1);
   }  // end of GetLength

   /// <summary>get string length</summary>
   inline size_t GetLength()
   {
      return(length);
   }  // end of GetLength

   inline size_t GetLength(char *string)
   {
      size_t l = 0;
      if (string == NULL)
         return(0);
      while (*string)
      {
         l++;
         string++;
      }
      return(l);
   }  // end of GetLength

   /// <summary>calculate string length using given buffer</summary>
   inline size_t ResetLength()
   {
      TCHAR *ps = string.Buffer;
      while (*ps)
         ps++;
      length = ps - string.Buffer;
      size_t mx = (string.GetSize()-1);
      if (mx < 0)
         mx = 0;
      if (length > mx)
         length = mx;
      return(length);
   }  // end of GetLength

   /// <summary>get string length in Bytes</summary>
   inline size_t GetSizeInBytes()
   {
      return(string.GetSizeInBytes());
   }  // end of GetSizeInBytes

   /// <summary>get string buffer value</summary>
   inline TCHAR *GetRawBuffer()
   {
      return(string.Buffer);
   }  // end of get_String

   /// <summary>get string buffer value</summary>
   inline TCHAR *GetBuffer()
   {
      if (string.Buffer == NULL)
         return(GetEmptyString());
      return(string.Buffer);
   }  // end of get_String

   /// <summary>copy a given ansi string value</summary>
   /// <param name="buffer">buffer to copy</param>
   /// <returns>the copied string is returned</returns>
   template< class T > 
   TCHAR *Overwrite(T *buffer, size_t bufferSize)
   {
      // validate that we can override the string
      size_t sz = string.GetSize() - 1;
      if (bufferSize > sz)
      {
         if (sz > 0)
            *string.Buffer = NULL;
         lastResult.ErrorNo = ERROR_INSUFFICIENT_BUFFER;
         return(NULL);
      }

      // copy the AnsiString into the Unicode string
      length = 0;
      TCHAR *b = string.Buffer;
      while(length < bufferSize)
      {
         *b = *buffer;
         b++;
         buffer++;
         length++;
      }
      *b = NULL;  // always null terminate strings
      
      return(GetBuffer());
   }  // end of Overwrite

   /// <summary>provide to copy string</summary>

   TCHAR *Copy(char *buffer, size_t bufferSize);
   TCHAR *Copy(char *buffer)
   {
      return(Copy(buffer,GetLength(buffer)));
   }

   TCHAR *Copy(TCHAR *buffer)
   {
      return(Copy(buffer,0));
   }

   TCHAR *Copy(TCHAR *buffer, size_t bufferSize);
   TCHAR *Copy(String *buffer, size_t bufferSize)
   {
      if (buffer == NULL)
         return(NULL);
      return(Copy(buffer->GetBuffer(),bufferSize));
   }

   static char *Copy(char *outBuffer, size_t bufferSize, char *inBuffer)
   {
      Memory::copy<char>(outBuffer,(DWORD)bufferSize,inBuffer);
      return(outBuffer);
   }

   static wchar_t *Copy(wchar_t *outBuffer, size_t bufferSize, wchar_t *inBuffer)
   {
      Memory::copy<wchar_t>(outBuffer,(DWORD)bufferSize,inBuffer);
      return(outBuffer);
   }

   static wchar_t *Copy(wchar_t *outBuffer, size_t bufferSize, char *inBuffer)
   {
      size_t inSize = getLength(inBuffer);
      Memory::copyACharToWChar(
         outBuffer,(DWORD)bufferSize,inBuffer,(DWORD)inSize);
      return(outBuffer);
   }

   TCHAR *Copy(String *buffer)
   {
      if (buffer == NULL)
         return(NULL);
      return(Copy(buffer->GetBuffer(),buffer->GetLength()));
   }

   TCHAR *Copy(String &buffer)
   {
      return(Copy(buffer.GetBuffer(),buffer.GetLength()));
   }

   TCHAR *Copy(String &buffer, size_t bufferSize)
   {
      return(Copy(buffer.GetBuffer(),bufferSize));
   }

   static void Clear(TCHAR *outBuffer, size_t bufferSize, TCHAR clearValue)
   {
      Memory::clear<TCHAR>(outBuffer,(DWORD)bufferSize,clearValue);
   }

   /// <summary>provide to concatenate strings</summary>
   TCHAR *Concat(TCHAR *buffer, size_t bufferSize);
   TCHAR *Concat(String *buffer)
   {
      if (buffer == NULL)
         return(NULL);
      return(Concat(buffer->GetBuffer(),buffer->GetLength()));
   }
   TCHAR *Concat(String &buffer)
   {
      return(Concat(buffer.GetBuffer(),buffer.GetLength()));
   }
   TCHAR *Concat(TCHAR *buffer)
   {
      size_t bufferSize = GetLength(buffer);
      return(Concat(buffer,bufferSize));
   }
   TCHAR *Concat(char *buffer, size_t bufferSize)
   {
      String str;
      str.Copy(buffer,bufferSize);
      return(Concat(str));
   }
   TCHAR *Concat(char *buffer)
   {
      String str;
      size_t bufferSize = AnsiString::getLength(buffer);
      str.Copy(buffer,bufferSize);
      return(Concat(str));
   }
   TCHAR *Concat(long number);

   /// <summary>allocate the string buffer with given size any previously
   /// allocate buffer will be lost</summary>
   inline TCHAR *AllocBuffer(size_t size)
   {
      string.Dispose();
      string.Alloc(size);
      if (string.Buffer == NULL)
         return(NULL);
      *string.Buffer = NULL;
      ValidateBuffer();
      return(GetBuffer());
   }  // end of AllocBuffer

   TCHAR *Trim();
   TCHAR *ToLower();
   TCHAR *ToUpper();

   static TCHAR *ToLower(TCHAR *string);
   static TCHAR *ToUpper(TCHAR *string);

   /// <summary>compare char1 with char2</summary>
   /// <param name="char1">char 1</param>
   /// <param name="char2">char 2</param>
   /// <returns>returns 0 if equal, 1 if c2 > c1 else -1</returns>
   static inline int CompareChars(TCHAR char1, TCHAR char2)
   {
      int result;
      if (char1 == char2)
         result = 0;
      else
      if (char1 < char2)
         result = 1;
      else
         result = -1;
      return(result);
   }  // end of Compare

   /// <summary>compare given char with a char in the current string buffer
   /// at a position specified by given index with char2</summary>
   /// <param name="character">character to compare too</param>
   /// <returns>returns 0 if equal, 1 if character > buffer-char
   /// else -1</returns>
   inline int Compare(DWORD index, TCHAR character)
   {
      if (string.Buffer == NULL)
         return(BadCompareReturnValue);
      if ((index < 0) || (index >= length))
         return(BadIndexValue);

      return(CompareChars(*(string.Buffer + index), character));
   }  // end of Compare

   /// <summary>compare the given string buffer1 with current buffer2 Given
   /// buffers most be a null-terminated strings</summary></summary>
   /// <param name="buffer1">string buffer1 to compare with</param>
   /// <param name="buffer2">string buffer2 to compare too</param>
   /// <returns>returns 0 if equal, 1 if buffer2 > buffer1
   /// else -1</returns>
   static inline int Compare(TCHAR *buffer1,TCHAR *buffer2)
   {
      if (buffer1 == NULL)
         return(BadCompareReturnValue);
      if (buffer2 == NULL)
         return(BadCompareReturnValue);

      int r;
      TCHAR *c1 = buffer1;
      TCHAR *c2 = buffer2;
      while (*c1)
      {
         r = CompareChars(*c1,*c2);
         if (r != 0)
            return(r);
         c1++;
         c2++;
      }

      if (*c1 == *c2)
         r = 0;
      else
      if (*c1 < *c2)
         r = 1;
      else
         r = -1;
      return(r);
   }  // end of Compare (buffers)

   /// <summary>compare the given string buffer1 with current buffer2 Given
   /// buffers most be a null-terminated strings</summary></summary>
   /// <param name="buffer1">string buffer1 to compare with</param>
   /// <param name="buffer2">string buffer2 to compare too</param>
   /// <returns>returns 0 if equal, 1 if buffer2 > buffer1
   /// else -1</returns>
   static inline int Compare(
      TCHAR *buffer1, size_t buffer1Length, TCHAR *buffer2, size_t buffer2Length)
   {
      if (buffer1 == NULL)
         return(BadCompareReturnValue);
      if (buffer2 == NULL)
         return(BadCompareReturnValue);

      int r;
      TCHAR *c1 = buffer1;
      TCHAR *c2 = buffer2;

      size_t minLen = buffer1Length < buffer2Length ? buffer1Length : buffer2Length;
      if (minLen < 0)
         minLen = 0;

      while (*c1 && minLen)
      {
         r = CompareChars(*c1,*c2);
         if (r != 0)
            return(r);
         c1++;
         c2++;
         minLen--;
      }

      if ((*c1 == *c2) || (minLen == 0))
         r = 0;
      else
      if (*c1 < *c2)
         r = 1;
      else
         r = -1;
      return(r);
   }  // end of Compare (buffers)

   /// <summary>compare the given string buffer with current-buffer. Given
   /// buffer most be a null-terminated string</summary>
   /// <param name="buffer">string buffer to compare too</param>
   /// <returns>returns 0 if equal, 1 if buffer > current-buffer
   /// else -1</returns>
   inline int Compare(TCHAR *buffer)
   {
      return(Compare(string.Buffer,buffer));
   }  // end of Compare (buffers)

   /// <summary>return the current string as an ansi string</summary>
   static AnsiString *ToAnsiString(wchar_t *buffer);
   AnsiString *ToAnsiString();

   /// <summary>return the current string as an ansi string</summary>
   static String *Substring(int start, int length,String *sourceString);
   String *Substring(int start, int length)
   {  return(Substring(start,length,this)); }

   // --------------------------------------------------------------------------

   static TCHAR *FindBinaryItem(
      TCHAR *sourceBuffer,size_t sourceLength, TCHAR *text,size_t textLength);
   static TCHAR *FindString(
      TCHAR *sourceBuffer,size_t sourceLength, TCHAR *text,size_t textLength);
   static char *FindString(
      char *sourceBuffer,size_t sourceLength, char *text,size_t textLength);

   // --------------------------------------------------------------------------

   static TCHAR *GetUniqueId(String &uniqueId);
   static void GetPathAndFileName(
      TCHAR *filePath, String &path, String &fileName);
   static BYTE *ToByteArray(TCHAR *buffer, size_t bufferLength);

   static inline bool IsNullOrEmpty(TCHAR *text)
   {
      if (text == NULL)
         return true;
      if (*text == NULL)
         return true;

      while (*text)
      {
         if (*text <= ' ')
            text++;
         else
            break;
      }

      return *text == NULL;
   }  // end of IsNullOrEmpty

}  ;  // end of String class

// -----------------------------------------------------------------------------

typedef struct _ItemKeyValue
{
private:
public:

   String Key;
   String Value;

   bool SetKeyValue(String &line);
   inline int Compare(TCHAR *key)
   {
      return(Key.Compare(key));
   }

   void Dispose()
   {
      Key.Dispose();
      Value.Dispose();
   }

}  ItemKeyValue ;  // end of MessageLineKeyValue

// -----------------------------------------------------------------------------

}  // end of Kif::Win32
}  // end of Kif

